package com.xstudio.pvzreborn.recipe.machine.polarcraftingtable;

import com.google.gson.JsonObject;
import com.xstudio.pvzreborn.block.BlockNames;
import com.xstudio.pvzreborn.mixin.MixinShapedRecipe;
import com.xstudio.pvzreborn.mixin.MixinShapelessRecipe;
import com.xstudio.pvzreborn.recipe.RecipeSerializerBase;
import com.xstudio.pvzreborn.recipe.machine.MachineRecipeBase;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public abstract class PCTRecipeBase extends MachineRecipeBase {

    public static final String TYPE_ID = BlockNames.POLAR_CRAFTING_TABLE;

	protected final List<Ingredient> inputs;
	protected final ItemStack output;
	protected final int requireEnergy;
	protected final int tick;

	public PCTRecipeBase(ResourceLocation id, ItemStack output, List<Ingredient> inputs, int requireEnergy, int tick) {
		super(id);
		this.tick = tick;
		this.output = output;
		this.inputs = inputs;
		this.requireEnergy = requireEnergy;
	}

	public abstract boolean matches(List<ItemStack> actualStacks, int haveEnergy);

	@Override
	public int getTick() {
		return tick;
	}

	@Override
	public int getRequireEnergy() {
		return requireEnergy;
	}

	public List<Ingredient> getInputs() {
		return inputs;
	}

	@Override
	public String getTypeId() {
		return TYPE_ID;
	}

	@NotNull
	@Override
	public ItemStack getResultItem() {
		return output;
	}

	public static class Serializer extends RecipeSerializerBase<PCTRecipeBase> {

		private static List<Ingredient> getPCTShapedRecipeInput(JsonObject json) {
			Map<String, Ingredient> map = MixinShapedRecipe.keyFromJson(GsonHelper.getAsJsonObject(json, "defines"));
			String[] pattern = MixinShapedRecipe.shrink(MixinShapedRecipe.patternFromJson(GsonHelper.getAsJsonArray(json, "pattern")));
			return MixinShapedRecipe.dissolvePattern(pattern, map, pattern[0].length(), pattern.length);
		}

		@Nullable
		@Override
		public PCTRecipeBase fromNetwork(@NotNull ResourceLocation id, FriendlyByteBuf pBuffer) {
			ItemStack output = pBuffer.readItem();
			int tick = pBuffer.readVarInt();
			int requireEnergy = pBuffer.readVarInt();
			int length = pBuffer.readVarInt();
			boolean isShaped = pBuffer.readBoolean();
			ArrayList<Ingredient> inputs = new ArrayList<>(length);
			for (int i = 0; i < length; i++) {
				inputs.add(Ingredient.fromNetwork(pBuffer));
			}
			if (isShaped) {
				return new PCTShapedRecipe(id, output, inputs, requireEnergy, tick);
			}
			return new PCTShapelessRecipe(id, output, inputs, requireEnergy, tick);
		}

		@NotNull
		@Override
		public PCTRecipeBase fromJson(@NotNull ResourceLocation id, @NotNull JsonObject json) {
			int tick = json.get("tick").getAsInt();
			boolean isShaped = json.get("isShaped").getAsBoolean();
			int requireEnergy = json.get("requireEnergy").getAsInt();
			ItemStack output = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "output"));
			if (isShaped) {
				return new PCTShapedRecipe(id, output, getPCTShapedRecipeInput(json), requireEnergy, tick);
			}
			return new PCTShapelessRecipe(id, output, MixinShapelessRecipe.itemsFromJson(GsonHelper.getAsJsonArray(json, "inputs")), requireEnergy, tick);
		}

		@Override
		public void toNetwork(FriendlyByteBuf pBuffer, PCTRecipeBase pRecipe) {
			pBuffer.writeItem(pRecipe.getResultItem());
			pBuffer.writeVarInt(pRecipe.getTick());
			pBuffer.writeVarInt(pRecipe.getRequireEnergy());
			pBuffer.writeVarInt(pRecipe.getInputs().size());
			pBuffer.writeBoolean(!pRecipe.isShapeless(pRecipe));
			for (Ingredient ingredient : pRecipe.getInputs()) {
				ingredient.toNetwork(pBuffer);
			}
		}

	}

}
